from sqlalchemy import Table, create_engine
from scopt.util import message as msg_util
from scopt.util.misc import accept
import model
from . import handlers
from scopt.util import sqlalchemy_util

_REGISTRY_HANDLERS = handlers.token.registry()


class Registry():
    def __init__(self, config):
        url = config.get('SECURITY', 'url')
        data_dir = config.get('APP', 'DATA_DIR')
        self.__url = url.replace('{DATA_DIR}', data_dir).replace('\\', '/')
        self.__metadata = model.get()
        self.__registry_init(config)
        self.__connection = None
        self.__engine = None

    def __registry_init(self, config):
        engine = create_engine(self.__url, echo=False)
        self.__metadata.create_all(engine)
        self.__connection = engine.connect()
        tx = self.__connection.begin()
        try:
            self.delete('users',
                        where=[['users.admin', True]])
            self.insert('users',
                        values={'login': config.get('APP', 'admin_login'),
                                'username': 'Administrator',
                                'md5pwd': config.get('APP', 'admin_pass_md5'),
                                'admin': True})
            tx.commit()
        except:
            tx.rollback()
            raise
        finally:
            self.__connection.close()
            self.__connection = None

    @accept(status=['AFP'])
    def __call__(self, data_packet):
        # TODO: Prior to any call connection must be validated
        if self.__connection is None:
            self.__engine = create_engine(self.__url, echo=False)
            self.__connection = self.__engine.connect()
        security_token = msg_util.get_security_token(data_packet)
        if security_token is None:
            data_packet = msg_util.exception(data_packet,
                                             'security.missing.token')
        else:
            token_type = security_token['type']
            if token_type not in _REGISTRY_HANDLERS:
                data_packet = msg_util.exception(data_packet,
                                                 'security.invalid.token.type')
            else:
                token_handler = _REGISTRY_HANDLERS[token_type]
                data_packet = token_handler(data_packet, self)
        return data_packet

    def table(self, table_name):
        return Table(table_name, self.__metadata)

    def execute(self, command):
        return self.__connection.execute(command)

    def query(self, tables, columns=None, where=None, order=None,
              mapping=None):
        q = sqlalchemy_util.query(self.__metadata, tables, columns, where,
                                      order, mapping)
        result = self.execute(q)
        rows = result.fetchall()
        result.close()
        return rows

    def update(self, table_name, values, where=None, mapping=None):
        u = sqlalchemy_util.update(self.__metadata, table_name, values,
                                   where, mapping)
        self.execute(u)

    def delete(self, table_name, where=None, mapping=None):
        d = sqlalchemy_util.delete(self.__metadata, table_name, where, mapping)
        self.execute(d)

    def insert(self, table_name, values, mapping=None):
        i = sqlalchemy_util.insert(self.__metadata, table_name, values,
                                   mapping)
        self.execute(i)
